/*
 * @Author: intellectual seeker 3336339701@qq.com
 * @Date: 2024-12-19 10:48:08
 * @LastEditors: intellectual seeker 3336339701@qq.com
 * @LastEditTime: 2024-12-19 12:05:18
 * @FilePath: /linux-learning/code/lesson23/mystdio.c
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include "mystdio.h"

const char* toString(int flush_mode)
{
    if(flush_mode & LINE_FLUSH)
    {
        return "LINE";
    }
    else if(flush_mode & FULL_FLUSH)
    {
        return "FULL";
    }
    else if(flush_mode & NONE_FLUSH)
    {
        return "NONE";
    }
    else
    {
        return "unKown";
    }
}

//Segmentation fault 段错误，访问非法空间
void DebugPrint(_myFILE* fp)
{
    printf("outbuffer: %s\n", fp->outbuffer);
    printf("cap: %d\n", fp->cap);
    printf("pos: %d\n", fp->pos);
    printf("fp: %d\n", fp->fileno);
    printf("flush_mode: %s\n", toString(fp->flush_mode));
}

_myFILE* myfopen(const char* pathname, const char* mode)
{
    //确定打开模式
    int flag = 0;//系统调用接口标识位
    if(strcmp(mode, "r") == 0)
    {
        flag |= O_RDONLY;
    }
    else if(strcmp(mode, "w") == 0)
    {
        flag |= (O_WRONLY | O_CREAT | O_TRUNC);//O_TRUNC 清空文件覆盖式写入
    }
    else if(strcmp(mode, "a") == 0)
    {
        flag |= (O_WRONLY | O_CREAT | O_APPEND);
    }
    else
    {
        return NULL;
    }

    int fd = 0;
    if(flag & O_WRONLY)
    {
        umask(0);//重置权限掩码，权限掩码中出现的权限会去掉
        fd = open(pathname, flag, 0666);//设置文件权限，8进制，可读可写
    }
    else
    {
        fd = open(pathname, flag);
    }

    if(fd < 0) return NULL;
    
    _myFILE* fp = (_myFILE*)malloc(sizeof(_myFILE));
    if(fp == NULL) return NULL;

    fp->cap = SIZE;
    fp->pos = 0;
    fp->fileno = fd;
    fp->flush_mode = LINE_FLUSH;//默认刷新模式设置为行刷新

    return fp;
}

void my_fflush(_myFILE* fp)
{
    if(fp->pos == 0) return;
    write(fp->fileno, fp->outbuffer, fp->pos);
    fp->pos = 0;//刷新后，缓存区清空
}

int myfwrite(_myFILE* fp, const char* s, int size)
{
    memcpy(fp->outbuffer + fp->pos, s, size);
    fp->pos += size;
    //判断刷新模式
    if((fp->flush_mode & LINE_FLUSH) && fp->outbuffer[fp->pos - 1] == '\n')//行刷新
    {
        my_fflush(fp);
    }
    else if((fp->flush_mode & FULL_FLUSH) && fp->cap == fp->pos)//全刷新
    {
        my_fflush(fp);
    }

    return size;
}

void myfclose(_myFILE* fp)
{
    my_fflush(fp);//关闭文件前强制刷新
    close(fp->fileno);
    free(fp);
}